# -*- coding: utf-8 -*-
"""
@Time    : 2024/7/12 11:41 
@Author  : ZhangShenao 
@File    : download_by_future.py 
@Desc    : 使用Future实现异步网页下载

Future表示一个异步操作的执行结果
它会将处于等待状态的操作包裹起来放到队列中,这些操作的状态随时可以查询
Future在执行完成后,也可以获取结果或异常
"""
import concurrent.futures

import requests

from bacis.decorator.perf_log_decorator import perf_log


def download_site(url: str) -> None:
    """
    从网页下载内容
    :param url: 网页url
    """

    try:
        resp = requests.get(url)
        print(f'download {len(resp.content)} from {url}')
    except Exception as err:
        print(f'download {url} error: {err}')


def download_all_sites_by_future(site_urls: list[str]) -> None:
    """
    通过Future机制并发执行,从多个网页下载内容
    :param site_urls: 网页url列表
    """

    # 创建线程池,并设置最大线程数=5
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        # 创建future list,用于保存执行结果
        futures = []

        # 遍历网页列表,向线程池中提交异步任务,并保存Future
        for url in site_urls:
            future = executor.submit(download_site, url)
            futures.append(future)

        # 遍历执行完成的Future,获取执行结果
        # Future完成的顺序并不与创建的顺序一致,取决于任务的执行时长和操作系统的线程调度
        for completed_future in concurrent.futures.as_completed(futures):
            completed_future.result()


@perf_log
def run():
    sites = [
        'https://en.wikipedia.org/wiki/Portal:Arts',
        'https://en.wikipedia.org/wiki/Portal:History',
        'https://en.wikipedia.org/wiki/Portal:Society',
        'https://en.wikipedia.org/wiki/Portal:Biography',
        'https://en.wikipedia.org/wiki/Portal:Mathematics',
        'https://en.wikipedia.org/wiki/Portal:Science',
        'https://en.wikipedia.org/wiki/Computer_science',
        'https://en.wikipedia.org/wiki/Python_(programming_language)',
        'https://en.wikipedia.org/wiki/Java_(programming_language)',
        'https://en.wikipedia.org/wiki/PHP',
        'https://en.wikipedia.org/wiki/Node.js',
        'https://en.wikipedia.org/wiki/The_C_Programming_Language',
        'https://en.wikipedia.org/wiki/Go_(programming_language)'
    ]
    download_all_sites_by_future(sites)


run()
